'''
Checks calibration source data for abnormalities indicative of improper deployment.
If abnormalities are found, sends email alerts


ERROR CODES
 form:
 XXX - # - i
 
    XXX: Type of error. 
        TOR torque error;
        POS position error;
        VEL velocity error;
        
    #: 0 or 1. 
        0 smaller than;
        1 greater than;
        
    i: index of error occurence in data


'''

import pickle
import os
import sys
from CalTorque import OpenCalTorqueDB
from CalTqFixOffset_Gauss import BinData
import matplotlib
from matplotlib import pyplot as PLT
from datetime import datetime

def ImportAverage(file = "pickled/pickled_3std_in.pkl"):
    jar = open(file, 'r')
    avg = pickle.load(jar)
    jar.close()
    return avg


def CheckTorque(positionData, torqueData):
    # get 3 sigma for y from a pickled average (this means the average should be redone after every calibration run?
    avg = ImportAverage()
    
    # x will be used to determine average location of occurrence
    
    x, y_min = BinData(avg['x'], avg['y'] - avg['y_std'])
    x, y_max = BinData(avg['x'], avg['y'] + avg['y_std'])
    xData, yData = BinData(positionData, torqueData)
    
    torqueErrorCount = 0
    
    ###NEED TO DIFFERENTIATE BETWEEN IN VS OUT
    for i, torque in enumerate(yData):
        if torque > y_max[i]:
            #print "ERROR", xData[i]
            error = error + "Torque value (at index" + str(i) + ") greater than 2 sigma. "
            errorCode.append("TOR-1-" + str(i))
            errorCount += 1
            torqueErrorCount += 1
        '''elif torque > y_min[i]: ## not really an issue
            error = error + "Torque value (at index" + str(i) + ") smaller than 2 sigma. " 
            errorCode.append("TOR-0-" + str(i))
            errorCount +=1'''
        
    if torqueErrorCount > 50:
        torqueError = True
    else:
        torqueError = False
        
    return torqueError, torqueErrorCount


def CheckPosition(initialPos, finalPos, station):
    # Compares final position to the actual position of the station deployed to
    # Determines whether the final position offset is acceptable
    
    posDiff = finalPos - initialPos
    
    if station == 'S2':
        pos = 338.9
    elif station == 'S5':
        pos = 392.6
    elif station == 'S8':
        pos = 445.7
    elif station == 'S11':
        pos = 501.7
    else:
        pos = posDiff
    
    if posDiff - pos > 0.2: # they're pretty much all true at a 0.2 tolerance
        positionError = True
        errorCode = "POS-0-" + station
    elif posDiff - pos < -0.2:
        positionError = True
        errorCode = "POS-1-" + station
    else:
        positionError = False
    
    # this can be in looping over error code list
    "Final position proximity to true station location is unsatisfactory. Details:" 
    # put limits in - if == 0, closer, elif == 1, farther "farther/ closer" than maxOffset "cm"
    "Deployment velocity dangerously high. Details:" ## give interval where it was too high?
    
    return positionError, errorCode
    # problematic for those runs where station is given, but it is truly S# + ##
    # would be better if could get the station/final position from the Comments section of the database
    # entry and interpret it.

def CheckVelocity(velocityData):
    return
    #What are the standards for these???

def RunProblemCheck(data): # this wont work for runs from one station to another
    # compare data to established qc standards
    # check for:
    # absolute torque too high
    # velocity too high
    # position not at a close enough distance to station
    
    errorCode = [] # gathers error codes
    errorCount = 0 # counts number of error occurences
    error = ""     # string containing error specifications
    
    # if true, trigger alert email
    torqueError, torqueErrorCount = CheckTorque(data.NewPosition(), data.Torque())
    positionError, code = CheckPosition(data['pos_offsetfix'][0], data['pos_offsetfix'][-1], data['station'])
    velocityError = False
    
    
    checkList = [torqueError, velocityError, positionError]
    print checkList #have it return an array of the problem(s), and the details (a string?)
    #print errorCode
    #print errorCount
    '''
    # loop over errorCode list
    for x, error in enumerate(errorCode):
        errType = error.split('-')[0]
        errSize = error.split('-')[1]
        errIndex = error.split('-')[-1]
        
        # error type            NESTED IF STATEMENTS???
        if errType == "TOR":
            message = "Torque value  exceeds 2 sigma. Details:"
            
            if errSize == 1: ## greater, by how much?
                details = "at index " + errIndex + ", torque = " + data[torque_inoz][errIndex] + "in.oz. That is " (data[torque_inoz][errIndex] - SIGMA[errIndex]) + "in.oz greater than 2 sigma."
            else:
                print "that was an else for torque"
            
        #elif errType == "POS":
        #    message = "Final position proximity to true station location is unsatisfactory. Details:"
        #    
        #    if erroSize == 1:
        #        details = delta + "beyond Station location (" + stationLocation + ")"
        
        #elif errType == "VEL":
        
        error = error + "\nError" + str(x) + ":" + message + details ### or if repeated error at diff position, just list locations and details
    '''
    '''
    fig = PLT.figure(figsize=(15,8),dpi=150)
    box = [0.14, 0.14, 0.76, 0.76]
    ax1 = fig.add_axes(box)
    ax1.plot(x, y_min, '-', color = 'g')
    ax1.plot(x, y_max, '-', color = 'b')
    ax1.plot(x, yData, '-', color = 'r')
    PLT.title("Number of error occurences: " + str(errorCount))
    PLT.savefig('test/' + str(data['date'].strftime('%Y%m%d')) + '.png')
    '''
    return checkList, error#, details
    
    '''
    # only return error and details if there is and error
    for item in checkList:
        if item == False:
            return error, details
            break
    '''


def SendEmail(checkList):

    ### use email or smtplib or nntplib package to do this
            
    mailList = [] # list of emails to send alert to
    #do stuff that sends email to mail list
    # list (write) problems to email & other info
    # attach plots to email



def ToBeMainFunction():

    
    # input: new run that was submitted (where and how, what format?)
    # -- have a boolean stored as a data field that tracks if the data was run through
    # -- or check all runs since a certain date, then update date
    
    database = OpenCalTorqueDB()
    
    # get data objects that need to be checked
    for run in database:
        if run.Datetime.strftime() < someDate: continue
        
        # details = [run date, source, station, details of alert]
        
        # check run data for potential problems
        checkList = RunProblemCheck(run)
    
        # if problem found, send email
        for problem in checkList:
            if problem == True:
                print "Problem located. Sending email alert."
                SendEmail(details)
                break
        

def GetTestRunData(path):
    book = OpenCalTorqueXLS(path)
    data = GetSheetData(book)
    
    return data

def main(argv = sys.argv):
    pass


if __name__ == "__main__":
    main(sys.argv)
    